/**
 *
 */
package com.naiterui.ehp.bs.doctor.service.impl;

import java.util.*;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.naiterui.ehp.bp.domain.DrPatientGroupDetail;
import com.naiterui.ehp.bp.domain.PatientGroup;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.utils.lang.StringUtil;
import com.naiterui.ehp.bs.doctor.dao.IDrPatientGroupDetailDao;
import com.naiterui.ehp.bs.doctor.dao.IPatientGroupDao;
import com.naiterui.ehp.bs.doctor.exception.ExceptionCodes;
import com.naiterui.ehp.bs.doctor.service.IPatientGroupService;
import com.naiterui.ehp.bs.doctor.service.IPatientService;
import com.naiterui.ehp.bs.doctor.utils.CollectionUtil;
import com.naiterui.ehp.bs.doctor.vo.PatientGroupVo;
import com.naiterui.ehp.bs.doctor.vo.PatientUserGroupVo;
import com.naiterui.ehp.bs.doctor.vo.PatientVo;

/**
 * @Description 概述
 */
@Service
public class AdPatientGroupServiceImpl implements IPatientGroupService {

    private static final Logger LOGGER = LoggerFactory.getLogger(AdPatientGroupServiceImpl.class);

    @Autowired
    private IPatientGroupDao patientGroupDao;
    @Autowired
    private IPatientService patientService;
    @Autowired
    private IDrPatientGroupDetailDao drPatientGroupDetailDao;

    /**
     * Title: findPatientGroupByDoctorId
     * @param doctorId
     * @return
     * @throws BusinessException
     * @see IPatientGroupService#findPatientGroupByDoctorId(java.lang.Long)
     */
    @Override
    public List<PatientGroupVo> findPatientGroupByDoctorId(Long doctorId) {
        return findPatientGroupByDoctorId(doctorId, false);
    }

    /**
     * findPatientGroupByDoctorId
     * @since
     * @param doctorId 医生ID
     * @param filterEmpty 是否过滤掉空分组
     * @return
     * @History 2017年6月28日 by wangchuan
     * @see IPatientGroupService#findPatientGroupByDoctorId(java.lang.Long,
     *      boolean)
     */
    @Override
    public List<PatientGroupVo> findPatientGroupByDoctorId(Long doctorId, boolean filterEmpty) {
        List<PatientGroup> list = patientGroupDao.getPatientGroupList(doctorId);
        List<PatientGroupVo> voList = new ArrayList<>();
        // 分组下的患者计数map
        Map<Long, Long> patientCountInGroup = drPatientGroupDetailDao.getPatientCountInGroup(doctorId);
        for (PatientGroup group : list) {
            Long groupId = group.getId();
            // 分组内患者计数
            Long patientCount = patientCountInGroup.get(groupId);
            long count = patientCount == null ? 0 : patientCount;
            // 过滤空分组
            if (filterEmpty && count <= 0) {
                continue;
            }

            PatientGroupVo vo = new PatientGroupVo();
            vo.setGroupName(group.getName());
            vo.setId(groupId);
            vo.setGroupCount(count);
            voList.add(vo);
        }
        return voList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveGroup(Long doctorId, String name) {
        // 创建新分组
        PatientGroup group = new PatientGroup();
        group.setName(name);
        group.setDoctorId(doctorId);
        group.setCreatedAt(new Date());
        group.setChangedAt(new Date());
        group.setCreatedBy("doctorSystem");
        group.setChangedBy("doctorSystem");
        patientGroupDao.save(group);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateGroup(Long doctorId, Long groupId, String name) throws BusinessException {
        // 修改分组
        PatientGroup group = patientGroupDao.get(groupId);
        if (group == null) {
            LOGGER.info("患者分组{}不存在", groupId);
            throw new BusinessException(ExceptionCodes.PATIENT_GROUP_NULL);
        }

        // 分组名有改动
        if (!name.equals(group.getName())) {
            if (findExsitGroupName(doctorId, name, groupId)) {
                LOGGER.info("患者分组{}已经存在", groupId);
                throw new BusinessException(ExceptionCodes.PATIENT_GROUP_EXSIT);
            }
            group.setName(name);
            group.setChangedAt(new Date());
            patientGroupDao.saveOrUpdate(group);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteGroup(Long groupId) {
        // 删除分组
        patientGroupDao.removeById(groupId);
        // 删除分组成员
        removeGroupDetail(groupId, null);
    }

    @Override
    public List<PatientUserGroupVo> findListUserGroup(Long groupId, Long doctorId) throws Exception {
        // 修改分组
        PatientGroup group = patientGroupDao.get(groupId);
        if (group == null) {
            LOGGER.info("患者分组不存在,分组id为:{}", groupId);
            throw new BusinessException(ExceptionCodes.PATIENT_GROUP_NULL);
        }

        // 分组下所有患者ID列表
        List<Long> patientIdList = drPatientGroupDetailDao.getPatientIdsByGroupId(groupId, doctorId);
        if (patientIdList.isEmpty()) {
            LOGGER.info("患者分组为空");
            return new ArrayList<>();
        }

        // 患者信息
        List<PatientVo> patientList = patientService.getPatientsByDoctorId(doctorId, patientIdList);
        List<PatientUserGroupVo> list =
            patientList.stream().map(vo -> new PatientUserGroupVo(groupId, vo.getId(), vo.getName(),
                vo.getPatientIcon(), vo.getRemarkName(), vo.getGender(), vo.getAge())).collect(Collectors.toList());
        return list;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveUser2Group(Long groupId, String patientIds) throws BusinessException {
        // 修改分组
        PatientGroup group = patientGroupDao.get(groupId);
        if (group == null) {
            LOGGER.info("分组不存在,分组id为:{}", groupId);
            throw new BusinessException(ExceptionCodes.PATIENT_GROUP_NULL);
        }

        List<Long> patientList = StringUtil.convertLongStr2List(patientIds, ",");
        // 操作分组详情表
        addGroupDetail(group.getId(), group.getDoctorId(), patientList);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteUser2Group(Long groupId, String patientIds) throws BusinessException {
        // 删除分组
        PatientGroup group = patientGroupDao.get(groupId);
        if (group == null) {
            LOGGER.info("患者分组不存在,分组id为:" + groupId);
            throw new BusinessException(ExceptionCodes.PATIENT_GROUP_NULL);
        }

        List<Long> patientList = StringUtil.convertLongStr2List(patientIds, ",");
        // 操作分组详情表
        removeGroupDetail(group.getId(), patientList);
    }

    @Override
    public boolean findExsitGroupName(Long doctorId, String groupName, Long groupId) {
        return patientGroupDao.findExistNameByDoctorId(doctorId, groupName, groupId);
    }

    /**
     * 向分组内添加患者
     * PatientGroupServiceImpl.addGroupDetail()
     * @Author guoyongxiang
     * @Date 2017年4月2日
     * @since 2.7.0
     * @param groupId
     * @param doctorId
     * @param patientIds
     */
    private void addGroupDetail(Long groupId, Long doctorId, List<Long> patientIds) {
        drPatientGroupDetailDao.savePatientsByGroupId(groupId, doctorId, patientIds);
    }

    /**
     * 从分组移除患者
     * PatientGroupServiceImpl.removeGroupDetail()
     * @Author guoyongxiang
     * @Date 2017年4月2日
     * @since 2.7.0
     * @param groupId
     * @param patientIds
     */
    private void removeGroupDetail(Long groupId, List<Long> patientIds) {
        drPatientGroupDetailDao.removePatientsByGroupId(groupId, patientIds);
    }

    @Override
    public List<PatientGroupVo> getGroupListByPatient(Long doctorId, Long patientId) {
        // 患者所在的分组列表，基本信息
        List<PatientGroup> patientGroupList = patientGroupDao.getGroupListByPatient(doctorId, patientId);
        List<PatientGroupVo> patientGroupVOList = new ArrayList<>();
        if (patientGroupList != null) {
            // 只显示分组名
            patientGroupList.forEach(group -> {
                PatientGroupVo groupVO = new PatientGroupVo();
                groupVO.setGroupName(group.getName());
                patientGroupVOList.add(groupVO);
            });
        }
        return patientGroupVOList;
    }

    @Override
    public List<PatientGroupVo> getGroupListByDoctor(Long doctorId, Long patientId) {
        // 组装分组vo，并做标记
        List<PatientGroupVo> groupVOList = new ArrayList<>();
        // 医生所有的分组
        List<PatientGroup> allGroupList = patientGroupDao.getPatientGroupList(doctorId);
        if (allGroupList == null) {
            LOGGER.info("医生{}没有分组", doctorId);
            return groupVOList;
        }

        // 患者所在分组的id
        Set<Long> groupIds = new HashSet<>();
        if (patientId != null) {
            // 患者所在的分组列表，基本信息
            List<PatientGroup> patientGroupList = patientGroupDao.getGroupListByPatient(doctorId, patientId);
            if (patientGroupList != null) {
                groupIds = patientGroupList.stream().map(PatientGroup::getId).collect(Collectors.toSet());
            }
        }

        // 如果患者id为空，则groupIds为空，不做（患者是否在分组中的）标记处理

        for (PatientGroup group : allGroupList) {
            PatientGroupVo groupVO = new PatientGroupVo();
            Long groupId = group.getId();
            groupVO.setId(groupId);
            groupVO.setGroupName(group.getName());
            // 标记出患者所在的分组
            if (groupIds.contains(groupId)) {
                groupVO.setIncluded(PatientGroupVo.PATIENT_INCLUDED_TRUE);
            } else {
                groupVO.setIncluded(PatientGroupVo.PATIENT_INCLUDED_FALSE);
            }
            groupVOList.add(groupVO);
        }
        return groupVOList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updatePatientIncluded(Long doctorId, Long patientId, String groupIds) throws BusinessException {
        // 最终患者所在的分组集合
        List<Long> groupIdList = StringUtil.convertLongStr2List(groupIds, ",");
        Set<Long> groupIdSet = new HashSet<>(groupIdList);
        LOGGER.info("医生{}操作患者{}分组，最终目标：{}", doctorId, patientId, groupIdSet);

        // 数据库中，患者所在分组的id
        Set<Long> patientGroupIdSet = new HashSet<>();
        // 患者所在的分组列表，基本信息
        List<PatientGroup> patientGroupList = patientGroupDao.getGroupListByPatient(doctorId, patientId);
        if (patientGroupList != null) {
            patientGroupIdSet = patientGroupList.stream().map(PatientGroup::getId).collect(Collectors.toSet());
        }
        LOGGER.info("医生{}操作患者{}分组，db：{}", doctorId, patientId, patientGroupIdSet);

        if (groupIdSet.isEmpty() && patientGroupIdSet.isEmpty()) {
            LOGGER.info("医生{}操作患者{}分组，患者没有在任何分组！", doctorId, patientId);
            return;
        }

        // 需要添加该患者的分组
        Set<Long> addIds = CollectionUtil.diffCollections(groupIdSet, patientGroupIdSet);
        LOGGER.debug("医生{}操作患者{}分组，add：{}", doctorId, patientId, addIds);
        if (!addIds.isEmpty()) {
            // 判断所有的分组是否存在
            long count = patientGroupDao.getGroupsCount(addIds);
            if (addIds.size() > count) {
                LOGGER.info("某些分组不存在，不能添加进分组详情！");
                throw new BusinessException(ExceptionCodes.PATIENT_SOME_GROUP_NOT_EXIST);
            }
            // 执行添加操作
            drPatientGroupDetailDao.savePatientByGroupIds(doctorId, patientId, addIds);
        }

        // 需要从中移除的分组
        Set<Long> removeIds = CollectionUtil.diffCollections(patientGroupIdSet, groupIdSet);
        LOGGER.debug("医生{}操作患者{}分组，remove：{}", doctorId, patientId, removeIds);
        if (!removeIds.isEmpty()) {
            // 执行移除操作
            drPatientGroupDetailDao.removePatientFromGroupIds(patientId, removeIds);
        }
    }

    @Override
    public Map<Long, List<String>> getGroupNameByDoctorIdAndPatientIds(Long doctorId, List<Long> patientIds) {
        List<PatientGroup> patientGroupList = patientGroupDao.getPatientGroupList(doctorId);
        Map<Long, String> groupName = patientGroupList.stream()
                                                      .collect(Collectors.toMap(PatientGroup::getId,
                                                              PatientGroup::getName));
        List<DrPatientGroupDetail> patientGroupDetails = drPatientGroupDetailDao.getDetailByDoctorId(doctorId,
                patientIds);
        Map<Long, List<String>> patientGroupName = patientIds.stream()
                                                             .collect(Collectors.toMap(e -> e, e -> new ArrayList<>()));
        patientGroupDetails.forEach(patientGroupDetail -> {
            Long patientId = patientGroupDetail.getPatientId();
            List<String> gorupNames = patientGroupName.get(patientId);
            gorupNames.add(groupName.get(patientGroupDetail.getGroupId()));
            patientGroupName.put(patientId, gorupNames);
        });
        return patientGroupName;
    }
}
